﻿#include "stream/webrtc_stream.h"

#include <api/create_peerconnection_factory.h>
#include <api/audio_codecs/builtin_audio_encoder_factory.h>
#include <api/audio_codecs/builtin_audio_decoder_factory.h>
#include <api/video_codecs/builtin_video_encoder_factory.h>
#include <api/video_codecs/builtin_video_decoder_factory.h>

#include "base/xrtc_global.h"
#include "codecs/external_video_encoder_factory.h"
#include "codecs/external_video_decoder_factory.h"

#include "base/xrtc_pusher.h"
#include "base/xrtc_player.h"

namespace xrtc {

class DummySetRemoteDescriptionObserver :
    public webrtc::SetRemoteDescriptionObserverInterface 
{
public:
    DummySetRemoteDescriptionObserver(WebRTCStream* stream) :
        stream_(stream) { }

    void OnSetRemoteDescriptionComplete(webrtc::RTCError error) override {
        if (error.ok()) { // 保存对端offer设置成功
            RTC_LOG(LS_INFO) << "set remote sdp success";
            stream_->CreateAnswer();
        }
        else { 
            RTC_LOG(LS_WARNING) << "set remote sdp failed: " <<
                error.message();
        }
    }

private:
    WebRTCStream* stream_;
};

class DummyCreateAnswerDescriptionObserver :
    public webrtc::CreateSessionDescriptionObserver 
{
public:
    DummyCreateAnswerDescriptionObserver(WebRTCStream* stream) :
        stream_(stream) { }

private:
    void OnSuccess(webrtc::SessionDescriptionInterface* desc) override { //创建本地answer成功
        stream_->SetLocalAnswer(desc);
    }
   
    void OnFailure(webrtc::RTCError error) override {
        RTC_LOG(LS_WARNING) << "create answer failed: " << error.message();
    }

private:
    WebRTCStream* stream_;
};

class DummySetLocalDescriptionObserver :
    public webrtc::SetLocalDescriptionObserverInterface 
{
public:
    DummySetLocalDescriptionObserver(WebRTCStream* stream) :
        stream_(stream) { }

private:
    void OnSetLocalDescriptionComplete(webrtc::RTCError error) override {
        if (error.ok()) { // 保存本地offer/answer成功
            RTC_LOG(LS_INFO) << "set local offer/answer success";
        }
        else {
            RTC_LOG(LS_WARNING) << "set local offer/answer failed: " << error.message();
        }
    }

private:
    WebRTCStream* stream_;
};

class DummyCreateOfferDescriptionObserver :
    public webrtc::CreateSessionDescriptionObserver {
public:
    DummyCreateOfferDescriptionObserver(WebRTCStream* stream) : stream_(stream) {}

private:
    void OnSuccess(webrtc::SessionDescriptionInterface* desc) override {
        stream_->SetLocalOffer(desc); //创建本地offer成功
    }

    void OnFailure(webrtc::RTCError error) override {
        RTC_LOG(LS_WARNING) << "create offer failed: " << error.message();
    }

private:
    WebRTCStream* stream_;
};

WebRTCStream::WebRTCStream(XRTCPusher* xrtc_pusher, std::string uid, const std::string roomId):
    uid_(uid),
    roomId_(roomId),
    xrtc_pusher_(xrtc_pusher)
{
}

WebRTCStream::WebRTCStream(XRTCPlayer* xrtc_player, std::string uid, const std::string roomId)
    :uid_(uid),
    roomId_(roomId),
    xrtc_player_(xrtc_player)
{

}

WebRTCStream::~WebRTCStream() {
}

bool WebRTCStream::Init() {
    // 1. 创建PeerConnectionFactory
    pc_factory = webrtc::CreatePeerConnectionFactory(
        XRTCGlobal::Instance()->network_thread(), // 网络线程
        XRTCGlobal::Instance()->worker_thread(),  // 工作线程
        nullptr, // 信令线程
        nullptr, // 默认音频设备
        webrtc::CreateBuiltinAudioEncoderFactory(), // 音频编码器工厂
        webrtc::CreateBuiltinAudioDecoderFactory(), // 音频解码器工厂
        CreateExternalVideoEncoderFactory(), // 视频编码器工厂
        CreateExternalVideoDecoderFactory(), // 视频解码器工厂
        nullptr, // 音频混音器，可以传递自定义的算法
        nullptr // 音频处理器，可以传递自定义3A算法
    );

    if (!pc_factory) {
        RTC_LOG(LS_WARNING) << "create peerconnection factory failed";
        return false;
    }

    // 2. 创建peerconnection
    webrtc::PeerConnectionInterface::RTCConfiguration config;
    config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;

    webrtc::PeerConnectionDependencies dep(this);
    auto pc_or_error = pc_factory->CreatePeerConnectionOrError(
        config, std::move(dep));
    if (!pc_or_error.ok()) {
        RTC_LOG(LS_WARNING) << "create peerconnection failed: "
            << pc_or_error.error().message();
        return false;
    }

    pc = pc_or_error.value();

    return true;
}

void WebRTCStream::SetRemoteOffer(const std::string& offer) {
    if (!pc) {
        return;
    }

    // 将offer字符串转换成SessionDescription
    absl::optional<webrtc::SdpType> sdp_type = webrtc::SdpTypeFromString("offer");
    webrtc::SdpParseError err;
    std::unique_ptr<webrtc::SessionDescriptionInterface> session_description =
        webrtc::CreateSessionDescription(*sdp_type, offer, &err);
    if (!session_description) {
        RTC_LOG(LS_WARNING) << "create session description failed: "  << err.description;
        return;
    }

    // 将session description设置到pc
    rtc::scoped_refptr<DummySetRemoteDescriptionObserver> observer =
        new rtc::RefCountedObject<DummySetRemoteDescriptionObserver>(this);
    pc->SetRemoteDescription(std::move(session_description), observer);
}

void WebRTCStream::SetRemoteAnswer(const std::string& answer)
{
    if (!pc) {
        return;
    }

    // 将answer字符串转换成SessionDescription
    absl::optional<webrtc::SdpType> sdp_type = webrtc::SdpTypeFromString("answer");
    webrtc::SdpParseError err;
    std::unique_ptr<webrtc::SessionDescriptionInterface> session_description =
        webrtc::CreateSessionDescription(*sdp_type, answer, &err);
    if (!session_description) {
        RTC_LOG(LS_WARNING) << "create session description failed: " << err.description;
        return;
    }

    // 将session description设置到pc
    rtc::scoped_refptr<DummySetRemoteDescriptionObserver> observer =
        new rtc::RefCountedObject<DummySetRemoteDescriptionObserver>(this);
    pc->SetRemoteDescription(std::move(session_description), observer);
}

void WebRTCStream::CreateOffer()
{
    if (!pc) {
        return;
    }

    webrtc::PeerConnectionInterface::RTCOfferAnswerOptions options;
    rtc::scoped_refptr<DummyCreateOfferDescriptionObserver> observer =
        new rtc::RefCountedObject<DummyCreateOfferDescriptionObserver>(this);
    pc->CreateOffer(observer, options); //创建offer
}


void WebRTCStream::CreateAnswer() {
    if (!pc) {
        return;
    }

    rtc::scoped_refptr<DummyCreateAnswerDescriptionObserver> observer =
        new rtc::RefCountedObject<DummyCreateAnswerDescriptionObserver>(this);
    pc->CreateAnswer(observer, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions()); //创建Answer
}

void WebRTCStream::SetLocalOffer(webrtc::SessionDescriptionInterface* desc)
{
    std::string offer;
    desc->ToString(&offer);

    RTC_LOG(LS_INFO) << "create offer success, offer: \n" << offer;

    //SignalAnswerReady(this, answer);
    SendOffer(offer);

    if (!pc) {
        return;
    }

    rtc::scoped_refptr<DummySetLocalDescriptionObserver> observer =
        new rtc::RefCountedObject<DummySetLocalDescriptionObserver>(this);

    //保存本地offer
    std::unique_ptr<webrtc::SessionDescriptionInterface> offer_desc(desc);
    pc->SetLocalDescription(std::move(offer_desc), observer);
}

void WebRTCStream::SetLocalAnswer(webrtc::SessionDescriptionInterface* desc) 
{
    std::string answer;
    desc->ToString(&answer);

    RTC_LOG(LS_INFO) << "create answer success, answer: \n" << answer;

    //SignalAnswerReady(this, answer);
    SendAnswer(answer);

    if (!pc) {
        return;
    }

    rtc::scoped_refptr<DummySetLocalDescriptionObserver> observer =
        new rtc::RefCountedObject<DummySetLocalDescriptionObserver>(this);

    std::unique_ptr<webrtc::SessionDescriptionInterface> answer_desc(desc);
    pc->SetLocalDescription(std::move(answer_desc), observer);
}

void WebRTCStream::OnSignalingChange(
    webrtc::PeerConnectionInterface::SignalingState new_state) 
{
}

void WebRTCStream::OnDataChannel(
    rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) 
{
}

void WebRTCStream::OnIceCandidate(
    const webrtc::IceCandidateInterface* candidate) 
{
    std::string str_candidate;
    candidate->ToString(&str_candidate);
    RTC_LOG(LS_INFO) << "new candidate: " << str_candidate;

    if (xrtc_pusher_) {
        xrtc_pusher_->DoCandidate(candidate);
    }
    if (xrtc_player_) {
        xrtc_player_->DoCandidate(candidate);
    }
}

void WebRTCStream::OnIceGatheringChange(
    webrtc::PeerConnectionInterface::IceGatheringState new_state) 
{
}

void WebRTCStream::OnConnectionChange(
    webrtc::PeerConnectionInterface::PeerConnectionState new_state) 
{
    if (new_state ==  webrtc::PeerConnectionInterface::PeerConnectionState::kConnecting) 
    {
        SignalStreamState(this, XRTCStreamState::kConnecting);
    }
    else if (new_state == webrtc::PeerConnectionInterface::PeerConnectionState::kConnected) {
        SignalStreamState(this, XRTCStreamState::kConnected);
    }
    else if (new_state == webrtc::PeerConnectionInterface::PeerConnectionState::kDisconnected) {
        SignalStreamState(this, XRTCStreamState::kDisconnected);
    }
    else if (new_state == webrtc::PeerConnectionInterface::PeerConnectionState::kFailed ||
        new_state == webrtc::PeerConnectionInterface::PeerConnectionState::kClosed) 
    {
        SignalStreamState(this, XRTCStreamState::kFailed);
    }
}

void WebRTCStream::OnAddTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver,
    const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>& streams)
{
    SignalNewTrack(this, receiver);
    if (xrtc_pusher_) {
        xrtc_pusher_->DoRender(this, receiver);
    }
    if (xrtc_player_) {
        xrtc_player_->DoRender(this, receiver);
    }

}

void WebRTCStream::AddIceCandidate(std::string sdp_mid, int sdp_mlineindex, std::string sdp)
{
    webrtc::SdpParseError error;
    std::unique_ptr<webrtc::IceCandidateInterface> candidate(webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, sdp, &error));
    if (!candidate.get()) {
        RTC_LOG(WARNING) << "Can't parse received candidate message. " "SdpParseError was: " << error.description;
        return;
    }

    if (!pc->AddIceCandidate(candidate.get())) {
        RTC_LOG(WARNING) << "Failed to apply the received candidate";
        return;
    }

    RTC_LOG(LS_INFO) << "AddIceCandidate Sucess:\n" << sdp;
}

void WebRTCStream::SendAnswer(std::string const answer)
{
    if (xrtc_pusher_) {
        xrtc_pusher_->DoAnswer(answer);
    }
    if(xrtc_player_){
        xrtc_player_->DoAnswer(answer);
    }
}

void WebRTCStream::SendOffer(std::string const offer)
{
    if (xrtc_pusher_) {
        xrtc_pusher_->DoOffer(offer);
    }
}

} // namespace xrtc